const path = require("path");
const fs = require("fs");
const prettier = require("prettier");
const inquirer = require("inquirer");
const { log } = require("./utils");
const t = require("../config/dict");
const { boolChoies } = require("../config");

const defaults = {
  name: "PWA app",
  themeColor: "#4DBA87", // The Vue color
  msTileColor: "#000000",
  appleMobileWebAppCapable: "no",
  appleMobileWebAppStatusBarStyle: "default",
  assetsVersion: "",
  manifestPath: "manifest.json",
  manifestOptions: {},
  manifestCrossorigin: undefined,
};

const defaultManifest = {
  icons: [
    {
      src: "./img/icons/android-chrome-192x192.png",
      sizes: "192x192",
      type: "image/png",
    },
    {
      src: "./img/icons/android-chrome-512x512.png",
      sizes: "512x512",
      type: "image/png",
    },
    {
      src: "./img/icons/android-chrome-maskable-192x192.png",
      sizes: "192x192",
      type: "image/png",
      purpose: "maskable",
    },
    {
      src: "./img/icons/android-chrome-maskable-512x512.png",
      sizes: "512x512",
      type: "image/png",
      purpose: "maskable",
    },
  ],
  start_url: "index.html",
  display: "standalone",
  background_color: "#000000",
};

const defaultIconPaths = {
  faviconSVG: "img/icons/favicon.svg",
  favicon32: "img/icons/favicon-32x32.png",
  favicon16: "img/icons/favicon-16x16.png",
  appleTouchIcon: "img/icons/apple-touch-icon-152x152.png",
  maskIcon: "img/icons/safari-pinned-tab.svg",
  msTileImage: "img/icons/msapplication-icon-144x144.png",
};

function makeTag(tagName, attributes, voidTag = true) {
  return {
    tagName,
    voidTag,
    attributes,
  };
}

function isHrefAbsoluteUrl(href) {
  return /(http(s?)):\/\//gi.test(href);
}

function getTagHref(publicPath, href, assetsVersionStr) {
  let tagHref = `${href}${assetsVersionStr}`;
  if (!isHrefAbsoluteUrl(href)) {
    tagHref = `${publicPath}${tagHref}`;
  }
  return tagHref;
}

const htmlConfigContext = (context, options) => {
  const data = {
    headTags: [],
  };
  const {
    name,
    themeColor,
    msTileColor,
    appleMobileWebAppCapable,
    appleMobileWebAppStatusBarStyle,
    assetsVersion,
    manifestPath,
    iconPaths,
    manifestCrossorigin,
  } = options;

  const publicPath = "./";
  const assetsVersionStr = assetsVersion ? `?v=${assetsVersion}` : "";

  // Favicons
  if (iconPaths.faviconSVG != null) {
    data.headTags.push(
      makeTag("link", {
        rel: "icon",
        type: "image/svg+xml",
        href: getTagHref(publicPath, iconPaths.faviconSVG, assetsVersionStr),
      })
    );
  }
  if (iconPaths.favicon32 != null) {
    data.headTags.push(
      makeTag("link", {
        rel: "icon",
        type: "image/png",
        sizes: "32x32",
        href: getTagHref(publicPath, iconPaths.favicon32, assetsVersionStr),
      })
    );
  }
  if (iconPaths.favicon16 != null) {
    data.headTags.push(
      makeTag("link", {
        rel: "icon",
        type: "image/png",
        sizes: "16x16",
        href: getTagHref(publicPath, iconPaths.favicon16, assetsVersionStr),
      })
    );
  }

  if (themeColor != null) {
    data.headTags.push(
      makeTag("meta", {
        name: "theme-color",
        content: themeColor,
      })
    );
  }

  // Add to home screen for Safari on iOS
  data.headTags.push(
    /* makeTag("meta", {
      name: "apple-mobile-web-app-capable",
      content: appleMobileWebAppCapable,
    }), */
    makeTag("meta", {
      name: "apple-mobile-web-app-status-bar-style",
      content: appleMobileWebAppStatusBarStyle,
    })
    /* makeTag("meta", {
      name: "apple-mobile-web-app-title",
      content: context.name,
    }) */
  );
  /* if (iconPaths.appleTouchIcon != null) {
    data.headTags.push(
      makeTag("link", {
        rel: "apple-touch-icon",
        href: getTagHref(
          publicPath,
          iconPaths.appleTouchIcon,
          assetsVersionStr
        ),
      })
    );
  } */
  if (iconPaths.maskIcon != null) {
    data.headTags.push(
      makeTag("link", {
        rel: "mask-icon",
        href: getTagHref(publicPath, iconPaths.maskIcon, assetsVersionStr),
        color: themeColor,
      })
    );
  }

  // Add to home screen for Windows
  if (iconPaths.msTileImage != null) {
    data.headTags.push(
      makeTag("meta", {
        name: "msapplication-TileImage",
        content: getTagHref(
          publicPath,
          iconPaths.msTileImage,
          assetsVersionStr
        ),
      })
    );
  }
  if (msTileColor != null) {
    data.headTags.push(
      makeTag("meta", {
        name: "msapplication-TileColor",
        content: msTileColor,
      })
    );
  }

  return data;
};

const parseAttr = (attrs) => {
  let attrArr = [];
  for (let n in attrs) {
    attrArr.push(`${n}="${attrs[n]}"`);
  }
  return attrArr.join(" ");
};

const pwaParse = (context) => {
  try {
    const projectType = context.metadata.projectType[0].toLowerCase();
    const publicPath = path.resolve(
      process.cwd(),
      "./" + (context.metadata.projectDir || context.name) + "/"
    );

    defaults.assetsVersion = context.metadata.projectVersion;
    const options = Object.assign({ iconPaths: defaultIconPaths }, defaults);
    const data = htmlConfigContext(context, options);

    const { name, themeColor, manifestPath, manifestOptions } = options;
    const publicOptions = {
      name: context.name,
      short_name: name,
      theme_color: themeColor,
    };
    let mainfast = false;
    const mainfastFilePath = publicPath + "/" + manifestPath;
    if (fs.existsSync(mainfastFilePath)) {
      mainfast = fs.readFileSync(mainfastFilePath, "utf-8");
      mainfast = JSON.parse(mainfast);
    }
    const def = { ...defaultManifest };
    let startUrl =
      (/vite/.test(projectType) ? "/" : "/public/") + def.start_url;
    def.start_url = "." + startUrl;

    mainfast = JSON.stringify(
      Object.assign(mainfast || {}, publicOptions, def, manifestOptions)
    );

    fs.writeFileSync(
      mainfastFilePath,
      prettier.format(mainfast, {
        semi: false,
        parser: "json",
      })
    );
    log("success", {
      message: [
        t(context.lang, "初始化"),
        manifestPath,
        ",",
        t(context.lang, "完成"),
        t(context.lang, "。"),
      ].join(" "),
    });

    let startFilePath = publicPath + startUrl;
    if (!fs.existsSync(startFilePath)) {
      startFilePath = publicPath + startUrl.replace("public/", "");
      if (!fs.existsSync(startFilePath)) {
        log("error", {
          message: [
            t(context.lang, "初始化"),
            defaultManifest.start_url,
            ",",
            t(context.lang, "失败"),
            t(context.lang, "。"),
          ].join(" "),
        });
        return context;
      }
    }

    let startContext = fs.readFileSync(startFilePath, "utf-8");
    if (!/<link\s+rel="manifest"/.test(startContext))
      data.headTags.push({
        tagName: "link",
        voidTag: true,
        attributes: {
          rel: "manifest",
          href: (/vite/.test(projectType) ? "./" : "../") + manifestPath,
        },
      });

    for (let i = 0; i < data.headTags.length; i++) {
      let item = data.headTags[i];
      startContext = startContext.replace(
        /<\/head>/gim,
        `<${item.tagName} ${parseAttr(item.attributes)} /> </head>`
      );
    }
    fs.writeFileSync(
      startFilePath,
      prettier.format(startContext, {
        semi: false,
        parser: "html",
      })
    );
    log("success", {
      message: [
        t(context.lang, "初始化"),
        defaultManifest.start_url,
        ",",
        t(context.lang, "完成"),
        t(context.lang, "。"),
      ].join(" "),
    });
  } catch (e) {
    console.log(e);
    log("error", {
      message: [
        t(context.lang, "初始化"),
        t(context.lang, "失败"),
        t(context.lang, "。"),
      ].join(" "),
    });
  }
  return context;
};

module.exports = (context, filter) => {
  if (filter) {
    context.metadata.projectManifast = "yes";
    return pwaParse(context);
  }
  return inquirer
    .prompt([
      {
        name: "projectManifast",
        message: t(context.lang, "PWA") + "?",
        default: "yes",
        pageSize: 3,
        type: "rawlist",
        choices: [...t(context.lang, boolChoies)],
      },
    ])
    .then((answers) => {
      context.metadata.projectManifast = answers.projectManifast;
      if (answers.projectManifast === "yes") {
        return pwaParse(context);
      }
      return context;
    });
};
